/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package session.TX;

import entity.establishment.Stakeholder;
import helper.tx.Helper_LineBreakConverter;
import entity.tx.*;
import entity.tx.RewardVoucher;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

/**
 *
 * @author AdminNUS
 */
@Stateless
public class ULPSB implements ULPSBRemote {

    @PersistenceContext()
    EntityManager em;

    public ULPSB() {
    }

    public Integer calculateLoyaltyPoints(Date currentTrans, String customerEmail, Double subtotal) {
        System.out.println(">>> ULP Bean: Calculate loyalty points to be awarded");
        Users accts = new Users();
        int points = 0;
        Query q = em.createQuery("SELECT c from Users c where c.email = :paramCustomerEmail ");
        q.setParameter("paramCustomerEmail", customerEmail);

        accts = (Users) q.getSingleResult();
        if (accts == null) {
            System.out.println(">>> ULP Bean: user not found");
            return 0;
        }
        Double multipler = 0.0;
        accts.getEmail();

        Date recentTrans;
        try{
            recentTrans = accts.getMostRecentTransactionDate();
        }catch(NullPointerException e){
            recentTrans = currentTrans;
        }

        
        boolean isSame = compareMostRecentTransactionDate(recentTrans, currentTrans);
        if (isSame == true) {
            multipler = accts.getCustomerTier().getBonusMultiplier();
        } else {
            multipler = accts.getCustomerTier().getNormalMultiplier();
        }

        Double pts = (subtotal * multipler);

        points = pts.intValue();

        System.out.println(">>> ULP Bean: " + points + " to be awarded to user: " + customerEmail);

        return points;
    }

    public boolean compareMostRecentTransactionDate(Date recentTrans, Date currentTrans) {

        SimpleDateFormat formatter = new SimpleDateFormat("dd-MMM-yyyy");
        String mostRecentTransactionString = formatter.format(recentTrans);

        String currentTransactionString = formatter.format(currentTrans);

        if (mostRecentTransactionString.equals(currentTransactionString)) {
            return true;
        } else {
            return false;
        }




    }
    /*
     * Method to generate free points and award them to customer
     * This method is called when a customer makes a transaction
     * and the amount of points he earns is computed based on the amount of money he spent.
     */

    public void awardPoints(long userID, int pointsToAward) {
        Users customer = em.find(Users.class, userID);
        int points = customer.getLoyaltypoint() + pointsToAward;
        customer.setLoyaltypoint(points);
        em.flush();
    }

    //Randall: 15-oct-2011
    public void stakeholderCreateRewardItem(
            String stakeholder,
            String reward_Name,
            String reward_Description,
            Integer reward_Cost,
            Integer vouchers_left,
            boolean unlimitedVouchers) {

        //System.out.println("************************************** \n" + reward_Description);

        String str = Helper_LineBreakConverter.convertLineBreaks(reward_Description);
        
        RewardItem reward = new RewardItem(
                stakeholder,
                reward_Name,
                str,
                reward_Cost,
                vouchers_left,
                unlimitedVouchers);

        em.persist(reward);
    }

    //Randall: 15-oct-2011
    public void stakeholderDeleteRewardItem(long rewardItem_id) {
        System.out.println(">>> ULPBean: Attempt to delete reward with the ID: " + rewardItem_id);
        RewardItem reward = em.find(RewardItem.class, rewardItem_id);

        if (reward == null) {
            System.out.println(">>> ULPBean: Attempt to find reward item with ID: " + rewardItem_id + " failed.");
            return;
        }
        em.remove(reward);
        System.out.println(">>> ULPBean: Delete Success");
    }

    //Randall: 15-oct-2011
    public List<RewardItem> getRewardsByStakeholder(String stakeholderName) {
        List<RewardItem> returnList = new ArrayList<RewardItem>();
        Query q = em.createQuery("SELECT c from RewardItem c WHERE c.stakeholder = :paramStakeholder");
        q.setParameter("paramStakeholder", stakeholderName);

        for (Object o : q.getResultList()) {
            RewardItem temp = (RewardItem) o;
            returnList.add(temp);
        }
        return returnList;
    }
    
    
    public List<RewardItem> getAllRewards() {
        List<RewardItem> returnList = new ArrayList<RewardItem>();
        Query q = em.createQuery("SELECT c from RewardItem c");
        for (Object o : q.getResultList()) {
            RewardItem temp = (RewardItem) o;
            returnList.add(temp);
        }
        return returnList;
    }
    
    
    
    //This method is used to retrieve a user's loyalty points. It also checks for expiry and sets the points to zero if the expiry date is reached
    public Integer getUserLoyaltyPoints(String email){
        Users user = findCustomer(email);
        if (user==null) return 0;
        else{     
            
            //Check expiry
            Date expiryDate = new Date();
            Date today = new Date();
            Integer points = 0;
            
            if(user.getExpirydate() == null){
                if(user.getLoyaltypoint() == null) {
                    user.setLoyaltypoint(0);
                    return user.getLoyaltypoint();
                }
                else return user.getLoyaltypoint();
            }

            

            
            if(today.after(expiryDate)){
                user.setLoyaltypoint(0);
                em.flush();
            }
            return user.getLoyaltypoint();
        }
    }
    
    
    //This method returns the most recent transaction date and the points expiry date, separated by one whitespace
    public String getUserPointsExpiryStatus(String email){
        Users user = findCustomer(email);
        if (user==null) return " ";
        else{
            SimpleDateFormat formatter = new SimpleDateFormat("dd-MMM-yyyy---kk-mm-ss");
            
            String string_mostRecentTransaction = "NO DATE";
            String string_pointsExpiryDate = "NO DATE";
            
            try{string_mostRecentTransaction = formatter.format(user.getMostRecentTransactionDate());}
            catch (NullPointerException e){
            }
            
            try{string_pointsExpiryDate = formatter.format(user.getExpirydate());}
            catch (NullPointerException e){
            }

            return string_mostRecentTransaction + " " + string_pointsExpiryDate;
        }
    }
    
    
    

    //Randall: 15-oct-2011
    //Method called when a user spends points to purchase a reward voucher
    public String buyVoucher(String customerEmail, long rewardItem_id) {
        Users customer = findCustomer(customerEmail);
        if (customer == null) {
            return "customer ID not foind";
        }

        //*** Find the reward item
        RewardItem reward = em.find(RewardItem.class, rewardItem_id);
        if (reward == null) {
            System.out.println(">>> ULPBean: Attempt to find reward item with ID: " + rewardItem_id + " failed.");
            return "reward ID not foind";
        }

        //*** Check if there are still vouchers left
        if (!reward.isUnlimitedVouchers()) {
            if (reward.getVouchers_left() < 1) {
                System.out.println(">>> ULPBean: No vouchers left for this reward");
                return "There are no Vouchers left to purchase for this reward!";
            }
        }

        //*** Check if the user has enough points
        Integer cost = reward.getReward_Cost();
        if (customer.getLoyaltypoint() < cost) {
            System.out.println(">>> ULPBean: Customer cannot afford the reward");
            return "Not enough points to purchase this voucher!";
        } else {
            RewardVoucher voucher = new RewardVoucher(
                    reward.getId(),
                    customer.getId(),
                    reward.getStakeholder(),
                    reward.getReward_Name(),
                    reward.getReward_Description(),
                    reward.getReward_Cost(),
                    new Date());

            if (!reward.isUnlimitedVouchers()) { //Deduct from the amount of vouchers left open to purchase
                reward.decrementVoucher();
            }
            em.persist(voucher);

            //deduct the points cost
            Integer points = customer.getLoyaltypoint() - reward.getReward_Cost();
            customer.setLoyaltypoint(points);

            //add the voucher into the user's list of vouchers
            List<RewardVoucher> temp = customer.getList_vouchers();
            temp.add(voucher);
            customer.setList_vouchers(temp);


            em.flush();
            return "Successfully purchased voucher: " + reward.getReward_Name() + " from " + reward.getStakeholder();
        }
    }

    //Randall: 15-oct-2011
    //When a customer redeems a voucher, the outlet manager must call this method to set the voucher entity's redeemed boolean to true
    public void redeemVoucher(long voucher_id) {
        System.out.println(">>> ULPBean: redeem voucher with the ID: " + voucher_id);
        RewardVoucher voucher = em.find(RewardVoucher.class, voucher_id);
        if (voucher == null) {
            System.out.println(">>> ULPBean: Voucher not found");
            return;
        }

        if (voucher.isRedeemed()) {
            System.out.println(">>> ULPBean: Voucher already redeemed");
            return;
        }

        voucher.setRedeemed(true);
        voucher.setRedemptionDate(new Date());
        em.flush();
        System.out.println(">>> ULPBean: Voucher successfully redeemed");
    }

    //Randall: 15-oct-2011
    //This method is called by the customer when he wants to view all of his purchased vouchers.
    public List<RewardVoucher> getVouchersByCustomer(long customerID) {
        Query q = em.createQuery("SELECT c FROM RewardVoucher c WHERE c.customer_id = :paramCustomerID");
        q.setParameter("paramCustomerID", customerID);

        List<RewardVoucher> returnList = new ArrayList<RewardVoucher>();
        for (Object o : q.getResultList()) {
            returnList.add((RewardVoucher) o);
        }

        return returnList;
    }

    //Randall: 15-oct-2011
    public List<RewardVoucher> getVouchersByCustomerAndStakeholder(String customerEmail, String stakeholderName) {
        List<RewardVoucher> returnList = new ArrayList<RewardVoucher>();

        Users customer = findCustomer(customerEmail);
        if (customer == null) {
            return returnList; //just return an empty list if cannot find the customer
        }
        long customerID = customer.getId();

        Query q = em.createQuery("SELECT c FROM RewardVoucher c WHERE c.stakeholder = :paramStakeholder AND c.customer_id = :paramCustomerID");
        q.setParameter("paramStakeholder", stakeholderName);
        q.setParameter("paramCustomerID", customerID);


        for (Object o : q.getResultList()) {
            returnList.add((RewardVoucher) o);
        }

        return returnList;
    }

    //Randall: 21-Oct-2011
    public void createPointPurchaseEntry_Stakeholder(Date date, String buyer, Double amountPaid) {
        PointsPurchaseRecord record = new PointsPurchaseRecord();
        record.setPurchaseDate(date);
        record.setBuyer(buyer);
        record.setBuyer_type("Stakeholder");
        record.setAmountPaid(amountPaid);
        em.persist(record);


        Query q = em.createQuery("SELECT c FROM Stakeholder c WHERE c.name = :paramName");
        q.setParameter("paramName", buyer);
        List resultList = q.getResultList();
        if (resultList.isEmpty()) {
            return;
        }


        Stakeholder stk = (Stakeholder) resultList.get(0);

        List<PointsPurchaseRecord> temp = stk.getPointsPurchaseLog();
        temp.add(record);
        stk.setPointsPurchaseLog(temp);
        em.flush();
    }

    public void createPointPurchaseEntry_Users(Date date, String buyer, Double amountPaid) {
        PointsPurchaseRecord record = new PointsPurchaseRecord();
        record.setPurchaseDate(date);
        record.setBuyer(buyer);
        record.setBuyer_type("Customer");
        record.setAmountPaid(amountPaid);
        em.persist(record);

        Users customer = findCustomer(buyer);
        if (customer == null) {
            return;
        }

        List<PointsPurchaseRecord> temp = customer.getPointsPurchaseLog();
        temp.add(record);
        customer.setPointsPurchaseLog(temp);
        
        

        
        
        //Update the expiry date of his loyalty points (5 years after most recent transaction)
        customer.setMostRecentTransactionDate(date);
        Calendar expiryDate = Calendar.getInstance();
        expiryDate.setTime(date); 
        expiryDate.add(Calendar.YEAR, 5);
        customer.setExpirydate(expiryDate.getTime());
        
        
        em.flush();
    }
    

    public boolean setUserLoyaltyPoints(String customerEmail, Integer loyaltyPoint) {
        Users user = findCustomer(customerEmail);
        try{
            user.setLoyaltypoint(loyaltyPoint);
            return true;
        }catch(Exception ex){
            return false;
        } 
    }
    
    public boolean setStakeholderLoyaltyPoints(String stakeholderName, Integer loyaltyPoint) {
        Stakeholder s = findStakeholderByName(stakeholderName);
        try{
            s.setLoyaltyPoints(loyaltyPoint);
            return true;
        }catch(Exception ex){
            return false;
        }
    }
    
    public boolean stalkerholderAwardPoints(String stakeholderName, Integer points, String customerEmail) {
        Query q = em.createQuery("SELECT c FROM Stakeholder c WHERE c.name = :paramName");
        q.setParameter("paramName", stakeholderName);
        List resultList = q.getResultList();
        if (resultList.isEmpty()) {
            return false;
        }
        Stakeholder stk = (Stakeholder) resultList.get(0);

        Users user = findCustomer(customerEmail);

        if (user == null) {
            return false;
        }

        Integer stkhldrPoints = stk.getLoyaltyPoints();


        if(points>stkhldrPoints)
            return false;
        
        if(points<=0)
            return false;
        
            Integer userPoints = this.getUserLoyaltyPoints(customerEmail);

            userPoints += points;

            stkhldrPoints -= points;

            user.setLoyaltypoint(userPoints);

            stk.setLoyaltyPoints(stkhldrPoints);

            em.flush();

            return true;
       
    }

    public Users findCustomer(String customerEmail) {
        System.out.println(">>> ULPBean: Try to find customer: " + customerEmail);

        Query q = em.createQuery("SELECT c from Users c where c.email = :paramCustomerEmail ");
        q.setParameter("paramCustomerEmail", customerEmail);

        List list = q.getResultList();
        //System.out.println(">>> ULPBean: " + list.size());
        if (list.isEmpty()) {
            System.out.println(">>> ULPBean: Attempt to find customer: " + customerEmail + " failed.");
            return null;
        } else {
            return (Users) list.get(0);
        }
    }
    
     public Stakeholder findStakeholderByName(String stakeholderName){
		Query q = em.createQuery("SELECT c FROM Stakeholder c WHERE c.name = :paramName AND c.isActivated = :paramActivation");
		q.setParameter("paramName", stakeholderName);
                q.setParameter("paramActivation", true);
		List resultList = q.getResultList();
		if(resultList.isEmpty()) return null;
		 
		
                Stakeholder stk = (Stakeholder) resultList.get(0);
		return stk;
	}
}
